import threading
import socket
import sys
import json
import time
import udp as pu
from config import seed
from proto import MType, Packet


class Node:
    seed = seed
    peers = {}
    myid = ""
    udp_socket = {}

    def rece(self):
        while 1:
            data, addr = pu.recembase(self.udp_socket)
            action = Packet.unpack(data)
            # print(action["type"])
            #     self.dispatch(action, addr)
            # def dispatch(self, action,addr):
            if action['t'] == MType.newPeer:
                # print("A new peer is coming")
                self.peers[action['d']] = addr
                # print(addr)
                pu.sendmbase(self.udp_socket, addr, Packet.pack(MType.peers, self.peers))

            if action['t'] == MType.peers:
                # print("Received a bunch of peers")
                self.peers.update(action['d'])
                # introduce yourself.
                pu.broadcastms(self.udp_socket, Packet.pack(MType.introduce, self.myid), self.peers)

            if action['t'] == MType.introduce:
                # print("Get a new friend.")
                self.peers[action['d']] = addr

            if action['t'] == MType.input:
                print(action['d'])

            if action['t'] == MType.exit:
                if self.myid == action['d']:
                    # cannot be closed too fast.
                    time.sleep(0.5)
                    break
                    # self.udp_socket.close()
                value, key = self.peers.pop(action['d'])
                print(action['d'] + " is left.")

    def startpeer(self):
        pu.sendmbase(self.udp_socket, self.seed, Packet.pack(MType.newPeer, self.myid))

    def send(self):
        while True:
            msg_input = input("$:")
            if msg_input == "exit":
                pu.broadcastms(self.udp_socket, Packet.pack(MType.exit, self.myid), self.peers)
                break
            if msg_input == "friends":
                print(self.peers)
                continue
            l = msg_input.split()
            if len(l) > 0 and l[-1] in self.peers.keys():
                toA = self.peers[l[-1]]
                s = ' '.join(l[:-1])
                pu.sendmbase(self.udp_socket, toA, Packet.pack(MType.input, s))
            else:
                pu.broadcastms(self.udp_socket, Packet.pack(MType.input, msg_input), self.peers)
                continue


def main():
    port = int(sys.argv[1])  # 从命令行获取端口号
    fromA = ("127.0.0.1", port)
    udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    udp_socket.bind((fromA[0], fromA[1]))
    peer = Node()
    peer.myid = sys.argv[2]
    peer.udp_socket = udp_socket
    # print(fromA, peer.myid)
    peer.startpeer()
    t1 = threading.Thread(target=peer.rece, args=())
    t2 = threading.Thread(target=peer.send, args=())

    t1.start()
    t2.start()


if __name__ == '__main__':
    main()

# usage:
# python main.py 8891 id1
# python main.py 8892 id2
# python main.py 8893 id3
